/*
This file is part of La Linea.

La Linea is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

La Linea is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with La Linea.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "globals.h"
#include "MainWindow.h"

MainWindow::MainWindow(){
	setWindowTitle(QString::fromUtf8("La Linea - Animation Editor"));
	setGeometry (50, 50, 800, 600);
	
	// Menus
	fileMenu = menuBar()->addMenu("&File");
    editMenu = menuBar()->addMenu("&Edit");
    displayMenu = menuBar()->addMenu("&Display");
	
	// Menu - File
	newAction = fileMenu->addAction("&New animation"); newAction->setIcon(QIcon("icons/new.png"));
	openAction = fileMenu->addAction("&Open"); openAction->setIcon(QIcon("icons/open.png"));
	saveAsAction = fileMenu->addAction("&Save as"); saveAsAction->setIcon(QIcon("icons/save.png"));
	saveAction = fileMenu->addAction("Save"); saveAction->setIcon(QIcon("icons/save.png"));
	quitAction = fileMenu->addAction("&Quit");
	
	newAction->setShortcut(QKeySequence("Ctrl+N"));
	openAction->setShortcut(QKeySequence("Ctrl+O"));
	saveAction->setShortcut(QKeySequence("Ctrl+S"));
	quitAction->setShortcut(QKeySequence("Ctrl+Q"));
	
	connect(newAction, SIGNAL(triggered()), this, SLOT(newAnimation()));
	connect(openAction, SIGNAL(triggered()), this, SLOT(openAnimation()));
	connect(saveAsAction, SIGNAL(triggered()), this, SLOT(saveAsAnimation()));
	connect(saveAction, SIGNAL(triggered()), this, SLOT(saveAnimation()));
	connect(quitAction, SIGNAL(triggered()), this, SLOT(close()));
	
	// Menu - Edit
	insertFrameMenu = editMenu->addMenu("Insert a new frame");
	
	insertFrameBeginAction = insertFrameMenu->addAction("Insert at the beginning");	
	connect(insertFrameBeginAction, SIGNAL(triggered()), this, SLOT(insertFrameBegin()));
	
	insertFrameEndAction = insertFrameMenu->addAction("Insert at the end");
	connect(insertFrameEndAction, SIGNAL(triggered()), this, SLOT(insertFrameEnd()));
	insertFrameEndAction->setShortcut(QKeySequence("Ctrl+I"));
	
	insertFrameBeforeAction = insertFrameMenu->addAction("Insert before the current frame");
	connect(insertFrameBeforeAction, SIGNAL(triggered()), this, SLOT(insertFrameBefore()));
	
	insertFrameAfterAction = insertFrameMenu->addAction("Insert after the current frame");
	connect(insertFrameAfterAction, SIGNAL(triggered()), this, SLOT(insertFrameAfter()));
	
	duplicateFrameMenu = editMenu->addMenu("Duplicate the current frame");
	
	duplicateFrameBeginAction = duplicateFrameMenu->addAction("Duplicate and insert at the beginning");	
	connect(duplicateFrameBeginAction, SIGNAL(triggered()), this, SLOT(duplicateFrameBegin()));
	
	duplicateFrameEndAction = duplicateFrameMenu->addAction("Duplicate and insert at the end");
	connect(duplicateFrameEndAction, SIGNAL(triggered()), this, SLOT(duplicateFrameEnd()));
	duplicateFrameEndAction->setShortcut(QKeySequence("Ctrl+D"));
	
	duplicateFrameBeforeAction = duplicateFrameMenu->addAction("Duplicate and insert before the current frame");
	connect(duplicateFrameBeforeAction, SIGNAL(triggered()), this, SLOT(duplicateFrameBefore()));
	
	duplicateFrameAfterAction = duplicateFrameMenu->addAction("Duplicate and insert after the current frame");
	connect(duplicateFrameAfterAction, SIGNAL(triggered()), this, SLOT(duplicateFrameAfter()));	
	
	clearFrameAction = editMenu->addAction("Clear the current frame");
	connect(clearFrameAction, SIGNAL(triggered()), this, SLOT(clearFrame()));	
	
	removeFrameAction = editMenu->addAction("Remove the current frame");
	connect(removeFrameAction, SIGNAL(triggered()), this, SLOT(removeFrame()));	
	
	editMenu->addSeparator();
	
	nextFrameAction = editMenu->addAction("Next frame");
	connect(nextFrameAction, SIGNAL(triggered()), this, SLOT(nextFrame()));
	nextFrameAction->setShortcut(QKeySequence("RIGHT"));
	previousFrameAction = editMenu->addAction("Previous frame");
	connect(previousFrameAction, SIGNAL(triggered()), this, SLOT(previousFrame()));
	previousFrameAction->setShortcut(QKeySequence("LEFT"));
	
	editMenu->addSeparator();
	
	increaseFrameAction = editMenu->addAction("Increase frame duration");	
	connect(increaseFrameAction, SIGNAL(triggered()), this, SLOT(increaseFrameDuration()));
	increaseFrameAction->setShortcut(QKeySequence("UP"));
	decreaseFrameAction = editMenu->addAction("Decrease frame duration");
	connect(decreaseFrameAction, SIGNAL(triggered()), this, SLOT(decreaseFrameDuration()));
	decreaseFrameAction->setShortcut(QKeySequence("DOWN"));
	
	editMenu->addSeparator();
	removeNodeAction = editMenu->addAction("Remove selected node");		
	connect(removeNodeAction, SIGNAL(triggered()), this, SLOT(deleteSelectedNode()));
	removeNodeAction->setShortcut(QKeySequence("DEL"));
	
	editMenu->addSeparator();
	
	editModeMenu = editMenu->addMenu("Edit Mode");
	editModeActionGroup = new QActionGroup(this);
	editPointsAction = editModeMenu->addAction("Edit points");
	editStencilAction = editModeMenu->addAction("Edit stencil");
	connect(editPointsAction, SIGNAL(triggered()), this, SLOT(setEditPointsMode()));
	connect(editStencilAction, SIGNAL(triggered()), this, SLOT(setEditStencilMode()));
	editModeActionGroup->addAction(editPointsAction);
	editModeActionGroup->addAction(editStencilAction);
	editPointsAction->setCheckable(true);
	editStencilAction->setCheckable(true);
	editPointsAction->setChecked(true);
	
	editMenu->addSeparator();
	
	stencilMenu = editMenu->addMenu("Stencils");
	addPosStencilAction = stencilMenu->addAction("Add a (+) stencil");
	addNegStencilAction = stencilMenu->addAction("Add a (-) stencil");
	highlightStencilAction = stencilMenu->addAction("Highlight stencils");
	deleteFrameStencilsAction = stencilMenu->addAction("Delete stencils");
	connect(addPosStencilAction, SIGNAL(triggered()), this, SLOT(addPosStencil()));
	connect(addNegStencilAction, SIGNAL(triggered()), this, SLOT(addNegStencil()));
	connect(highlightStencilAction, SIGNAL(triggered()), this, SLOT(toogleDebugStencil()));
	connect(deleteFrameStencilsAction, SIGNAL(triggered()), this, SLOT(deleteFrameStencils()));
	addPosStencilAction->setShortcut(QKeySequence("Return"));
	addNegStencilAction->setShortcut(QKeySequence("Backspace"));
	highlightStencilAction->setCheckable(true);
	highlightStencilAction->setChecked(true);
	
	// Menu - Display
	displayPointsAction = displayMenu->addAction("Control points"); 
	displayPointsAction->setCheckable(true); displayPointsAction->setChecked(true);
	displayPointsAction->setIcon(QIcon("icons/displayPoints.png"));
	connect(displayPointsAction, SIGNAL(triggered()), this, SLOT(tooglePoints()));
	displayPointsAction->setShortcut(QKeySequence("F1"));
	
	displayCurvePointsAction = displayMenu->addAction("Curve points"); 
	displayCurvePointsAction->setCheckable(true);
	displayCurvePointsAction->setIcon(QIcon("icons/displayCurvePoints.png"));
	connect(displayCurvePointsAction, SIGNAL(triggered()), this, SLOT(toogleCurvePoints()));
	displayCurvePointsAction->setShortcut(QKeySequence("F2"));
	
	displayCurvesAction = displayMenu->addAction("Curves"); 
	displayCurvesAction->setCheckable(true);
	displayCurvesAction->setIcon(QIcon("icons/displayCurves.png"));
	connect(displayCurvesAction, SIGNAL(triggered()), this, SLOT(toogleCurves()));	
	displayCurvesAction->setShortcut(QKeySequence("F3"));
	
	displayBorderAction = displayMenu->addAction("Border"); 
	displayBorderAction->setCheckable(true);	
	displayBorderAction->setIcon(QIcon("icons/displayBorder.png"));
	connect(displayBorderAction, SIGNAL(triggered()), this, SLOT(toogleBorder()));
	displayBorderAction->setShortcut(QKeySequence("F4"));
	
	displayFinalAction = displayMenu->addAction("Final render");
	displayFinalAction->setCheckable(true);	displayFinalAction->setChecked(true);
	displayFinalAction->setIcon(QIcon("icons/displayFinalRender.png"));
	connect(displayFinalAction, SIGNAL(triggered()), this, SLOT(toogleFinal()));
	displayFinalAction->setShortcut(QKeySequence("F5"));
	
	displayBoundingBox = displayMenu->addAction("Bounding box");
	displayBoundingBox->setCheckable(true); displayBoundingBox->setChecked(true);
	connect(displayBoundingBox, SIGNAL(triggered()), this, SLOT(toogleBoundingBox()));
	displayBoundingBox->setShortcut(QKeySequence("F6"));
	
	displayMenu->addSeparator();
	
	displayGhostAction = displayMenu->addAction("Ghost"); 
	displayGhostAction->setCheckable(true);
	displayGhostAction->setChecked(true);
	displayGhostAction->setIcon(QIcon("icons/ghost.png"));
	connect(displayGhostAction, SIGNAL(triggered()), this, SLOT(toogleGhost()));
	displayGhostAction->setShortcut(QKeySequence("Ctrl+H"));
	
	displayGridAction = displayMenu->addAction("Grid");
	displayGridAction->setCheckable(true);
	displayGridAction->setChecked(true);
	displayGridAction->setIcon(QIcon("icons/grid.png"));
	connect(displayGridAction, SIGNAL(triggered()), this, SLOT(toogleGrid()));	
	displayGridAction->setShortcut(QKeySequence("Ctrl+G"));
	
	displayMenu->addSeparator();
	
	increaseQualityAction = displayMenu->addAction("Quality++");
	connect(increaseQualityAction, SIGNAL(triggered()), this, SLOT(increaseQuality()));	
	increaseQualityAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Plus));
	
	decreaseQualityAction = displayMenu->addAction("Quality--");	
	connect(decreaseQualityAction, SIGNAL(triggered()), this, SLOT(decreaseQuality()));	
	decreaseQualityAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Minus));
	
	displayMenu->addSeparator();
	
	chooseBackgroundColorAction = displayMenu->addAction("Background color");
	connect(chooseBackgroundColorAction, SIGNAL(triggered()), this, SLOT(chooseBackgroundColor()));
	
	toogleOSDAction = displayMenu->addAction("OSD");
	toogleOSDAction->setCheckable(true);
	toogleOSDAction->setChecked(true);
	connect(toogleOSDAction, SIGNAL(triggered()), this, SLOT(toogleOSD()));
				
	displayMenu->addSeparator();
	
	playAction = displayMenu->addAction("Play / Pause"); playAction->setCheckable(true);
	playAction->setIcon(QIcon("icons/play.png"));
	connect(playAction, SIGNAL(triggered()), this, SLOT(tooglePlay()));
	playAction->setShortcut(QKeySequence("P"));
	
	// Toolbar
	toolbar = addToolBar("Toolbar");
	toolbar->addAction(newAction);
	toolbar->addAction(openAction);
	toolbar->addAction(saveAction);
	toolbar->addSeparator();
	toolbar->addAction(displayPointsAction);
	toolbar->addAction(displayCurvePointsAction);
	toolbar->addAction(displayCurvesAction);
	toolbar->addAction(displayBorderAction);
	toolbar->addAction(displayFinalAction);
	toolbar->addSeparator();
	toolbar->addAction(displayGhostAction);
	toolbar->addAction(displayGridAction);
	toolbar->addSeparator();
	toolbar->addAction(playAction);
	toolbar->addSeparator();
	
	editModeButton = new QToolButton(this);
	editModeButton->setMenu(editModeMenu);
	editModeButton->setPopupMode( QToolButton::MenuButtonPopup);
	editModeButton->setText("Edit points");
	toolbar->addWidget(editModeButton);
	
	
	// Informations dock
	informationsDock = new QDockWidget("Informations", this);
	informationsDock->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable);
    addDockWidget(Qt::LeftDockWidgetArea, informationsDock);

    informationsDockContent = new QWidget();
    informationsDock->setWidget(informationsDockContent);
	
	informationsDockLayout = new QVBoxLayout();
	
	informationsTree = new QTreeView(); // Tree displaying the animation's structure
	informationsTree->header()->hide();
	connect(informationsTree, SIGNAL(clicked(QModelIndex)), this, SLOT(selectInformationsTree(QModelIndex)));
	
	informationsTable = new QTableView(); // Table displaying property of the selected object		
	informationsTable->horizontalHeader()->hide(); 
	informationsTable->verticalHeader()->hide();
	informationsTable->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
	informationsTable->verticalHeader()->setDefaultSectionSize(15);
	
	informationsDockLayout->addWidget(informationsTree);
	informationsDockLayout->addWidget(informationsTable);
	
	informationsDockContent->setLayout(informationsDockLayout);
	
	_currentAnimation = new Animation("NewAnimation");
	_currentAnimation->addFrame(new Frame());

	_currentFile = "";
	
	// Rendering engine
	_display = new DisplayWidget(_currentAnimation, this);
    setCentralWidget(_display);

	// Model
	_animationModel = new QStandardItemModel(this);
	
	_propertyModel = new PropertyItemModel(this);
	_propertyModel->setMode(PropertyItemModel::ANIMATION);
	_propertyModel->setAnimation(_currentAnimation);
	connect(_display, SIGNAL(nodeSelected(Node*)), this, SLOT(nodeSelected(Node*)));
	connect(_display, SIGNAL(nodeUpdated()), this, SLOT(nodeUpdated()));
	
	informationsTree->setModel(_animationModel);
	informationsTable->setModel(_propertyModel);
	updateInformationsTree();
	updateList();
}

void MainWindow::updateInformationsTree(){
	_animationModel->clear();
	QStandardItem* header = new QStandardItem(QString("%0").arg(_currentAnimation->getName().c_str()));
	header->setFlags(header->flags() & ~Qt::ItemIsEditable);
	header->setIcon(QIcon("icons/animation.png"));
	int frameNumber = _currentAnimation->getFrameNumber();
	for(int i=0; i < frameNumber; i++){
		QStandardItem* currentItem = new QStandardItem(QString("Frame %0").arg(i+1));
		currentItem->setFlags(currentItem->flags() & ~Qt::ItemIsEditable);
		currentItem->setIcon(QIcon("icons/frame.png"));
		header->appendRow(currentItem);
	}
	_animationModel->appendRow(header);
	informationsTree->setExpanded(header->index(), true);
}

void MainWindow::updateList(){
	_propertyModel->setAnimation(_currentAnimation);
	_propertyModel->update();
}

void MainWindow::newAnimation(){
	Animation* newAnim = new Animation("NewAnimation");
	newAnim->addFrame(new Frame());
	_display->unselect();
	_display->setAnimation(newAnim);
	delete _currentAnimation;
	_currentAnimation = newAnim;
	setWindowTitle(QString::fromUtf8("La Linea - Animation Editor"));	
	_currentFile = "";
	updateInformationsTree();
	updateList();
}

void MainWindow::openAnimation(){
	QString path = QFileDialog::getOpenFileName(this, "Open an animation", QString(), "Animation (*.anim *.txt)");
	if(path != NULL){	
		_display->unselect();
		_currentAnimation->loadAnim(path.toStdString().c_str());		
		setWindowTitle(QString::fromUtf8("La Linea - Animation Editor : ")+path);
		_currentFile = path;
	}
	updateInformationsTree();
	updateList();
}

void MainWindow::saveAsAnimation(){
	QString path = QFileDialog::getSaveFileName(this, "Save an animation", QString(), "Animation (*.anim)");
	if(path != NULL){
		_currentAnimation->saveAnim(path.toStdString().c_str());		
		setWindowTitle(QString::fromUtf8("La Linea - Animation Editor : ")+path);
		_currentFile = path;
	}
}

void MainWindow::saveAnimation(){
	if(_currentFile.size() == 0) saveAsAnimation();
	else {
		_currentAnimation->saveAnim(_currentFile.toStdString().c_str());
	}
}

void MainWindow::tooglePoints(){
	_display->tooglePoints();
}

void MainWindow::toogleCurvePoints(){
	_display->toogleCurvePoints();
}

void MainWindow::toogleCurves(){
	_display->toogleCurves();
}

void MainWindow::toogleBorder(){
	_display->toogleBorder();
}

void MainWindow::toogleFinal(){
	_display->toogleFinal();
}

void MainWindow::toogleBoundingBox(){
	_display->toogleBoundingBox();
}

void MainWindow::toogleGhost(){
	_display->toogleGhost();
}

void MainWindow::toogleGrid(){
	_display->toogleGrid();
}

void MainWindow::tooglePlay(){
	_display->tooglePlay();
}

void MainWindow::insertFrameBegin(){
	_display->insertFrameBegin();
	updateInformationsTree();
}

void MainWindow::insertFrameEnd(){
	_display->insertFrameEnd();
	updateInformationsTree();
}

void MainWindow::insertFrameBefore(){
	_display->insertFrameBefore();
	updateInformationsTree();
}

void MainWindow::insertFrameAfter(){
	_display->insertFrameAfter();
	updateInformationsTree();
}

void MainWindow::duplicateFrameBegin(){
	_display->duplicateFrameBegin();
	updateInformationsTree();
}

void MainWindow::duplicateFrameEnd(){
	_display->duplicateFrameEnd();
	updateInformationsTree();
}

void MainWindow::duplicateFrameBefore(){
	_display->duplicateFrameBefore();
	updateInformationsTree();
}

void MainWindow::duplicateFrameAfter(){
	_display->duplicateFrameAfter();
	updateInformationsTree();
}

void MainWindow::clearFrame(){
	_display->clearFrame();
}

void MainWindow::removeFrame(){
	_display->removeFrame();
	updateInformationsTree();
}

void MainWindow::previousFrame(){
	_display->previousFrame();
}

void MainWindow::nextFrame(){
	_display->nextFrame();
}

void MainWindow::increaseFrameDuration(){
	_display->increaseFrameDuration();
	updateList();
}

void MainWindow::decreaseFrameDuration(){
	_display->decreaseFrameDuration();
	updateList();
}

void MainWindow::deleteSelectedNode(){
	_display->deleteSelectedNode();
}

void MainWindow::setEditPointsMode(){
	editModeButton->setText("Edit points");
	_display->setEditPointsMode();
}

void MainWindow::setEditStencilMode(){
	editModeButton->setText("Edit stencil");
	_display->setEditStencilMode();
}

void MainWindow::increaseQuality(){
	quality++;
	_currentAnimation->invalidateFrames();
}

void MainWindow::decreaseQuality(){
	quality = quality>1?quality-1:quality;
	_currentAnimation->invalidateFrames();
}


void MainWindow::selectInformationsTree(const QModelIndex &index){
	_currentAnimation->setCurrentFrameNumber(index.row());
}

void MainWindow::chooseBackgroundColor() {
	QColor color = QColorDialog::getColor(QColor(0,99,36,1), this);
	if(color.isValid()){
		_display->setBackgroundColor(color.redF(), color.greenF(), color.blueF());
	}
}

void MainWindow::toogleOSD(){
	_display->toogleOSD();
}

void MainWindow::addPosStencil(){
	_display->confirmPosStencil();
}

void MainWindow::addNegStencil(){
	_display->confirmNegStencil();
}

void MainWindow::toogleDebugStencil(){
	_display->toogleDebugStencil();
}

void MainWindow::deleteFrameStencils(){
	_display->deleteFrameStencils();
}

void MainWindow::nodeSelected(Node* n){
	_propertyModel->setNode(n);
	if(n){
		_propertyModel->setMode(PropertyItemModel::NODE);
	}
	else{
		_propertyModel->setMode(PropertyItemModel::ANIMATION);
	}
	
	_propertyModel->update();
}

void MainWindow::nodeUpdated(){
	_propertyModel->update();
}